package prefix.util;

import java.io.BufferedInputStream;
import java.io.BufferedWriter;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.nio.channels.Channels;
import java.nio.channels.FileChannel;
import java.nio.channels.ReadableByteChannel;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;

import org.apache.commons.lang.StringUtils;


public class FileUtil {

    /**
     * Get a resource as a String
     * 
     * @param callingClass
     *            TODO
     * @param filename
     * @return
     * @throws IOException
     */
    public static <T> StringBuilder getResourceAsStringBuilder(Class<T> callingClass, String filename) throws IOException {
        BufferedInputStream qstream = new BufferedInputStream(callingClass.getResourceAsStream(filename));
        byte[] b = new byte[102400];
        StringBuilder sb = new StringBuilder();
        int l;
        while ((l = qstream.read(b)) != -1) {
            sb.append(new String(b, 0, l));
        }
        return sb;
    }

    public static void storeStringToFile(String content, String fileName, String folderName) throws IOException {

        if (StringUtils.isEmpty(fileName) || StringUtils.isEmpty(content) || StringUtils.isEmpty(folderName)) {
            return;
        }

        if (!new File(folderName).isDirectory()) {
            new File(folderName).mkdirs();
        }

        File f = new File(folderName + File.separator + fileName);

        FileOutputStream fos = null;
        try {
            fos = new FileOutputStream(f);
            fos.write(content.getBytes());
        } finally {
            IOUtil.closeQuietly(fos);
        }
    }

    public static void storeStringToFile(String filePath, String content) {
        if (StringUtils.isEmpty(filePath) || StringUtils.isEmpty(content))
            return;
        FileOutputStream fos = null;
        try {
            File f = new File(filePath);
            if (!f.exists())
                f.createNewFile();
            fos = new FileOutputStream(f);
            fos.write(content.getBytes());
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            IOUtil.closeQuietly(fos);
        }
    }
    
    public static void storeStringToFile(File file, String content) {
        if (file==null)
            return;
        FileOutputStream fos = null;
        try {
            
            if (!file.exists())
            	file.createNewFile();
            fos = new FileOutputStream(file);
            fos.write(content.getBytes());
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            IOUtil.closeQuietly(fos);
        }
    }


    public static String faststoreInputStreamToFile(InputStream is, String baseRoot, String fileName,
            DatePrecision datePrecision) {
        FileOutputStream fos = null;
        ReadableByteChannel srcCh = null;
        FileChannel dstCh = null;
        String path = "";
        try {

            // make directory to store the file
            StringBuilder myDirBuilder = new StringBuilder();
            DateFormat day = new SimpleDateFormat("dd");
            DateFormat year = new SimpleDateFormat("yyyy");
            DateFormat month = new SimpleDateFormat("MM");
            Date time = new Date();
            switch (datePrecision) {
            case DAILY:
                myDirBuilder.append(year.format(time) + File.separator + month.format(time) + File.separator
                        + day.format(time));
                break;
            case MONTHLY:
                myDirBuilder.append(year.format(time) + File.separator + month.format(time));
                break;
            case YEARLY:
            default:
                myDirBuilder.append(year.format(time));
                break;
            }

            // Write to the file system
            String dirName = baseRoot + File.separator + myDirBuilder.toString();

            // if a dir for this month-year doesn't exist, create it
            File dir = new File(dirName);
            dir.mkdirs();
            if (!dir.exists()) {
                System.out.println("Could not create directory " + dirName);
                return path;
            }
            File f = getSafeFolderChild(dir, fileName);
            // File f = new File(dirName + File.separator + fileName);
            if (f.exists()) {
                return path;
            }
            path = f.getPath();
            // race condition here if file is created externally between the
            // check for existence and file writing.

            try {
                srcCh = Channels.newChannel(is);
                dstCh = new FileOutputStream(f).getChannel();
                dstCh.transferFrom(srcCh, 0, Long.MAX_VALUE);
            } finally {
                if (srcCh != null)
                    srcCh.close();
                if (dstCh != null)
                    dstCh.close();
            }
        } catch (Throwable tr) {
            System.out.println("Error occured in storing string to file in folder " + baseRoot);
            tr.printStackTrace();
        } finally {
            IOUtil.closeQuietly(fos);
        }
        return path;

    }

    public static ByteArrayInputStream getByteArrayInputStream(InputStream is) throws IOException {
        byte[] data = null;
        ByteArrayOutputStream bao = null;
        try {
            byte[] buff = new byte[102400];
            int bytesRead = 0;
            bao = new ByteArrayOutputStream();
            while ((bytesRead = is.read(buff)) != -1) {
                bao.write(buff, 0, bytesRead);
            }

            data = bao.toByteArray();
        } finally {
            IOUtil.closeQuietly(is);
            IOUtil.closeQuietly(bao);
        }

        return new ByteArrayInputStream(data);

    }

    public static File getSafeFolderChild(String folder, String descendantPath) {
        return getSafeFolderDescendant(folder, descendantPath, true);
    }

    public static File getSafeFolderDescendant(String folder, String descendantPath) {
        return getSafeFolderDescendant(folder, descendantPath, false);
    }

    public static File getSafeFolderDescendant(String folder, String descendantPath, boolean directChildOnly) {
        return getSafeFolderDescendant(new File(folder), descendantPath, directChildOnly);
    }

    public static File getSafeFolderChild(File folder, String descendantPath) {
        return getSafeFolderDescendant(folder, descendantPath, true);
    }

    public static File getSafeFolderDescendant(File folder, String descendantPath) {
        return getSafeFolderDescendant(folder, descendantPath, false);
    }

    public static File getSafeFolderDescendant(File folder, String descendantPath, boolean directChildOnly) {
        try {
            File descendant = new File(folder, descendantPath).getCanonicalFile();
            File ancestor;
            if (directChildOnly) {
                ancestor = descendant.getParentFile();
            } else {
                ancestor = descendant;
                while (ancestor != null && !folder.equals(ancestor)) {
                    ancestor = ancestor.getParentFile();
                }
            }
            if (!folder.equals(ancestor)) {
                throw new IllegalArgumentException("Possible intentional misuse, trying to create folder "
                        + (directChildOnly ? "child" : "descendant") + " outside parent folder. Folder: '" + folder
                        + "', " + (directChildOnly ? "Child" : "Descendant") + " path '" + descendantPath
                        + "', Resolved path: '" + descendant + "'");
            }
            return descendant;
        } catch (IOException e) {
            throw new IllegalArgumentException("Invalid parameters. Folder: '" + folder + "', "
                    + (directChildOnly ? "Child" : "Descendant") + " path '" + descendantPath, e);
        }
    }

    public enum DatePrecision {
        YEARLY, MONTHLY, DAILY;
    }

    public static void storeBytesToFile(byte[] content, String fileName) throws IOException {

        if (StringUtils.isEmpty(fileName) || StringUtils.isEmpty(new String(content))) {
            return;
        }
        File file = new File(fileName);
        if (file.exists())
            return;
        FileOutputStream out = null;
        try {
            out = new FileOutputStream(file);
            out.write(content);
        } finally {
            IOUtil.closeQuietly(out);
        }

    }

    public static String convertInputStreamToString(InputStream is) throws IOException {
        ByteArrayOutputStream outStream = new ByteArrayOutputStream();
        byte[] data = new byte[4096];
        int count = -1;
        while ((count = is.read(data, 0, 4096)) != -1)
            outStream.write(data, 0, count);

        data = null;
        return new String(outStream.toByteArray(), "gb2312");
    }

    public static InputStream StringTOInputStream(String in) throws Exception {

        ByteArrayInputStream is = new ByteArrayInputStream(in.getBytes("gb2312"));
        return is;
    }

    public static void appendText(String filePath, String content) {

        File file = new File(filePath);
        if (!file.exists()) {
            file.mkdirs();
        }
        FileWriter fw = null;
        try {
            fw = new FileWriter(filePath, true);
            BufferedWriter bw = new BufferedWriter(fw);
            bw.newLine();
            bw.append(content);
            bw.flush();
            if (fw != null)
                fw.close();
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

}
